package com.wang.mystream;

import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * @author yandong
 */
public class StreamDemo1 {
    public static void main(String[] args) {
        test18();
        //test17();
        //test16();
        //test15();
        //test14();
        //test13();
        //test12();
        //test08();
        //test07();
        //test06();
        //test05();
        //test04();
        //test03();
        //test02();
        //test01();
        //test00();
    }

    private static List<Author> getAuthors() {
        // 数据初始化
        Author author1 = new Author(1L, "蒙多", 33, "一个从菜刀中明悟哲理的祖安人", null);
        Author author2 = new Author(2L, "亚拉索", 15, "狂风也追逐不上他的思考速度", null);
        Author author3 = new Author(3L, "易", 14, "是这个世界在限制他的思维", null);
        Author author4 = new Author(3L, "易", 14, "是这个世界在限制他的思维", null);

        // 书籍列表
        List<Book> books1 = new ArrayList<>();
        List<Book> books2 = new ArrayList<>();
        List<Book> books3 = new ArrayList<>();

        books1.add(new Book(1L, "刀的两侧是光明与黑暗", "哲学,爱情", 88, "用一把刀划分了爱恨"));
        books1.add(new Book(2L, "一个人不能死在同一把刀下", "个人成长,爱情", 99, "讲述如何从失败中明悟真理"));

        books2.add(new Book(3L, "那风吹不到的地方", "哲学", 85, "带你用思维去领略世界的尽头"));
        books2.add(new Book(3L, "那风吹不到的地方", "哲学", 85, "带你用思维去领略世界的尽头"));
        books2.add(new Book(4L, "吹或不吹", "爱情,个人传记", 56, "一个哲学家的恋爱观注定很难把他所在的时代理解"));

        books3.add(new Book(5L, "你的剑就是我的剑", "爱情", 56, "无法想象一个武者能对他的伴侣这么的宽容"));
        books3.add(new Book(6L, "风与剑", "个人传记", 100, "两个哲学家灵魂和肉体的碰撞会激起怎么样的火花呢？"));
        books3.add(new Book(6L, "风与剑", "个人传记", 100, "两个哲学家灵魂和肉体的碰撞会激起怎么样的火花呢？"));

        author1.setBooks(books1);
        author2.setBooks(books2);
        author3.setBooks(books3);
        author4.setBooks(books3);

        List<Author> authorList = new ArrayList<>(Arrays.asList(author1, author2, author3, author4));
        return authorList;
    }

    private static void test00() {
        List<Author> authors = getAuthors();

        // 打印所有年龄小于18的作家的名字, 并去重
        // (1) 匿名内部类写法
        authors.stream() // 把集合转换成流
                .distinct() // 去重
                .filter(new Predicate<Author>() { // 过滤 (根据过滤条件)
                    @Override
                    public boolean test(Author author) {
                        return author.getAge() < 18;
                    }
                })
                .forEach(new Consumer<Author>() {
                    @Override
                    public void accept(Author author) {
                        System.out.println(author.getName());
                    }
                });
        // (2) Lambda表达式优化
        authors.stream() // 把集合转换成流
                .distinct() // 去重
                .filter(author -> author.getAge() < 18)
                .forEach(author -> System.out.println(author.getName()));
    }

    /**
     * 单列集合转换为Stream流
     */
    private static void test01() {
        List<String> list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("c");
        Stream<String> listStream = list.stream();
        listStream.distinct()
                .filter(x -> !x.equals("c"))
                .forEach(System.out::println);
    }


    /**
     * 数组转换为Stream流
     */
    private static void test02() {
        int[] arr = new int[]{1, 2, 3, 4, 5, 5};
        // 数组转换成stream流
        // 方式1
        IntStream stream = Arrays.stream(arr);
        // 方式2
        Stream<int[]> stream1 =  Stream.of(arr);

        stream.distinct()
                .filter(x -> x > 2)
                .forEach(System.out::println);
    }

    /**
     * 双列集合转换为Stream流
     * 先将双列集合转换为单列集合，再转换为Stream流
     */
    private static void test03() {
        Map<String,Integer> map = new HashMap<>();
        map.put("a",1);
        map.put("b",2);
        map.put("c",3);

        map.entrySet().stream() // 获取map的entrySet集合 (双列集合 --> 单列集合)
                .filter(x -> x.getValue() > 1)
                .forEach(System.out::println);
    }

    /**
     * 打印所有姓名长度大于 1 的作家的姓名
     */
    private static void test04() {
        List<Author> authors = getAuthors();
        authors.stream()
                .filter(author -> author.getName().length() > 1)
                .forEach(author -> System.out.println(author.getName()));
    }

    /**
     * 打印所有作家的姓名
     */
    private static void test05() {
        List<Author> authors = getAuthors();
        // (1) 匿名内部类写法
        authors.stream()
                .map(new Function<Author, Integer>() {
                    @Override
                    public Integer apply(Author author) {
                        return author.getAge();
                    }
                })
                .map(new Function<Integer, Integer>() {
                    @Override
                    public Integer apply(Integer age) {
                        return age + 10;
                    }
                })
                .forEach(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer age) {
                        System.out.println(age);
                    }
                });

        // (2) Lambda表达式写法
        authors.stream()
                .map(author -> author.getAge())
                .map(age -> age + 10)
                .forEach(age -> System.out.println(age));
    }

    /**
     * 打印所有作家姓名, 并要求其中不能有重复元素
     */
    private static void test06() {
        List<Author> authors = getAuthors();
        authors.stream()
                .distinct()
                .forEach(author -> System.out.println(author.getName()));
    }

    /**
     * 对流中的元素按照年龄进行降序排序, 并且要求不能有重复的元素
     */
    private static void test07() {
        List<Author> authors = getAuthors();
        authors.stream()
                .distinct()
                .sorted(new Comparator<Author>() {
                    @Override
                    public int compare(Author o1, Author o2) {
                        return o2.getAge() - o1.getAge();
                    }
                })
                .forEach(author -> System.out.println(author.getAge()));
    }

    /**
     * 对流中的元素按照年龄进行降序排序, 并且要求不能有重复的元素, 然后打印其中年龄最大的两个作家的姓名
     */
    private static void test08() {
        List<Author> authors = getAuthors();
        authors.stream()
                .distinct()
                .sorted()
                .limit(2)
                .forEach(author -> System.out.println(author.getName()));
    }

    /**
     * 打印除了年龄最大的作家外的其他作家, 要求不能有重复元素 并且按照年龄降序排序
     */
    private static void test09() {
        List<Author> authors = getAuthors();
        authors.stream()
                .distinct()
                .sorted()
                .skip(1)
                .forEach(author -> System.out.println(author.getName()));
    }

    /**
     * 打印所有书籍的名字, 要求对重复的元素进行去重
     */
    private static void test10() {
        List<Author> authors = getAuthors();
        // 匿名内部类写法
        authors.stream()
                .flatMap(new Function<Author, Stream<Book>>() {
                    @Override
                    public Stream<Book> apply(Author author) {
                        return author.getBooks().stream();
                    }
                })
                .distinct()
                .forEach(new Consumer<Book>() {
                    @Override
                    public void accept(Book book) {
                        System.out.println(book.getName());
                    }
                });

        // Lambda表达式写法
        authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .distinct()
                .forEach(book -> System.out.println(book.getName()));
    }

    /**
     * 输出所有作家的名字
     */
    private static void test11() {
        List<Author> authors = getAuthors();
        authors.stream()
                .map(author -> author.getName())
                .forEach(name -> System.out.println(name));
    }

    /**
     * 打印作家所出的书籍数目, 注意删除重复元素
     */
    private static void test12() {
        List<Author> authors = getAuthors();
        long count = authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .distinct()
                .count();
        System.out.println(count);
    }

    /**
     * 分别获取这些作家的所出书籍的最高分和最低分并打印
     * Stream<Author> --> Stream<Book> --> Stream<Integer> --> 求值
     */
    private static void test13() {
        List<Author> authors = getAuthors();
        Optional<Integer> max = authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .map(book -> book.getScore())
                .max(new Comparator<Integer>() {
                    @Override
                    public int compare(Integer score1, Integer score2) {
                        return score1 - score2;
                    }
                });
        System.out.println(max.get());

        Optional<Integer> min = authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .map(book -> book.getScore())
                .min((score1, score2) -> score1 - score2);
        System.out.println(min.get());
    }

    /**
     * 获取一个存放所有作者名字的List集合
     */
    public static void test14() {
        List<Author> authors = getAuthors();
        List<String> collect = authors.stream()
                .map(author -> author.getName())
                .collect(Collectors.toList());
        System.out.println(collect);
    }

    /**
     * 获取一个包含所有书名的set集合
     */
    public static void test15() {
        List<Author> authors = getAuthors();
        Set<Book> collect = authors.stream()
                .flatMap(author -> author.getBooks().stream())
                .collect(Collectors.toSet());
        System.out.println(collect);
    }

    /**
     * 获取一个map集合
     * (要求: key为作者名, value为List<Book>)
     */
    public static void test16() {
        List<Author> authors = getAuthors();
        // (1) 匿名内部类写法
        Map<String, List<Book>> collect1 = authors.stream()
                .collect(Collectors.toMap(new Function<Author, String>() {
                    @Override
                    public String apply(Author author) {
                        return author.getName();
                    }
                }, new Function<Author, List<Book>>() {
                    @Override
                    public List<Book> apply(Author author) {
                        return author.getBooks();
                    }
                }));
        System.out.println(collect1);

        // (2) Lambda表达式写法
        Map<String, List<Book>> collect2 = authors.stream()
                .collect(Collectors.toMap(author -> author.getName(), author -> author.getBooks()));
        System.out.println(collect2);
    }

    /**
     * 判断是否有年龄在29岁以上的作家
     */
    private static void test17() {
        List<Author> authors = getAuthors();
        boolean anyMatch = authors.stream()
                .anyMatch(author -> author.getAge() > 29);
        System.out.println(anyMatch);
    }

    /**
     * 判断是否所有作家都是成年人
     */
    private static void test18() {
        List<Author> authors = getAuthors();
        boolean allMatch = authors.stream()
                .allMatch(author -> author.getAge() > 18);
        System.out.println(allMatch);
    }

    /**
     * 判断作家是否都没有超过100岁的
     */
    private static void test19() {
        List<Author> authors = getAuthors();
        boolean noneMatch = authors.stream()
                .noneMatch(author -> author.getAge() > 100);
        System.out.println(noneMatch);
    }

    /**
     * 获取任意一个年龄大于18的作家, 如果存在就输出他的名字
     */
    private static void test20() {
        List<Author> authors = getAuthors();
        Optional<Author> optionalAuthor = authors.stream()
                .filter(author -> author.getAge()>98)
                .findAny();
        optionalAuthor.ifPresent(author -> System.out.println(author.getName()));
    }

    /**
     * 获取一个年龄最小的作家, 并输出他的姓名
     */
    private static void test21() {
        List<Author> authors = getAuthors();
        Optional<Author> first = authors.stream()
                .sorted((o1, o2) -> o1.getAge() - o2.getAge())
                .findFirst();
        first.ifPresent(author -> System.out.println(author.getName()));

    }




}
